package com.fjl.utils;

import org.springframework.stereotype.Component;

@Component
public class SnowflakeIdGenerator {
    // 起始时间戳（2024-1-1）
    private static final long START_TIMESTAMP = 1704038400000L;

    // 每部分占用的位数
    private static final long SEQUENCE_BITS = 12;   // 序列号占用的位数
    private static final long MACHINE_BITS = 5;     // 机器ID占用的位数
    private static final long DATACENTER_BITS = 5;  //数据中心ID占用的位数

    // 每部分的最大值
    private static final long MAX_DATACENTER_NUM = ~(-1L << DATACENTER_BITS);
    private static final long MAX_MACHINE_NUM = ~(-1L << MACHINE_BITS);
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);

    // 各部分向左的位移
    private static final long MACHINE_SHIFT = SEQUENCE_BITS;
    private static final long DATACENTER_SHIFT = SEQUENCE_BITS + MACHINE_BITS;
    private static final long TIMESTAMP_SHIFT = DATACENTER_SHIFT + DATACENTER_BITS;

    // 数据中心ID和机器ID
    private long datacenterID;          // 数据中心ID
    private long machineID;             // 机器ID
    private long sequence = 0L;         // 序列号
    private long lastTimestamp = -1L;   //上次生成ID的时间戳

    private static final SnowflakeIdGenerator snowflakeIdGenerator = new SnowflakeIdGenerator(1, 1);

    private SnowflakeIdGenerator(){
    }

    // 构造函数
    private SnowflakeIdGenerator(long datacenterID, long machineID) {
        if (datacenterID > MAX_DATACENTER_NUM || datacenterID < 0) {
            throw new IllegalArgumentException("Datacenter ID exceeds limit");
        }
        if (machineID > MAX_MACHINE_NUM || machineID <0) {
            throw new IllegalArgumentException("Machine ID exceeds limit");
        }
        this.datacenterID = datacenterID;
        this.machineID =machineID;
    }

    public static SnowflakeIdGenerator getSnowflakeIdGenerator(){
        return snowflakeIdGenerator;
    }

    // 生成唯一ID
    public synchronized long nextID() {
        long currentTimestamp = getCurrentTimestamp();

        // 检查时钟回拨
        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate ID.");
        }

        if (currentTimestamp == lastTimestamp) {
            // 同一毫秒内，自增序列
            sequence = (sequence + 1) & MAX_SEQUENCE;
            // 如果序列号超过最大值，等待下一毫秒
            if (sequence == 0L) {
                currentTimestamp = waitUntilNextMillis();
            }
        } else {
            // 不同毫秒内，重置序列号
            sequence = 0L;
        }

        lastTimestamp = currentTimestamp;

        // 生成ID
        return ((currentTimestamp - START_TIMESTAMP) << TIMESTAMP_SHIFT)
                | (datacenterID << DATACENTER_SHIFT)
                | (machineID << MACHINE_SHIFT)
                | sequence;
    }

    // 等待直到下一毫秒
    private long waitUntilNextMillis() {
        long timestamp = getCurrentTimestamp();
        while (timestamp <= lastTimestamp) {
            timestamp = getCurrentTimestamp();
        }
        return timestamp;
    }

    // 获取当前时间戳（毫秒）
    private long getCurrentTimestamp() {
        return System.currentTimeMillis();
    }
}
